package com.tinyshardingjdbc.tinyshardingjdbc.shardingasync;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tinyshardingjdbc.tinyshardingjdbc.shardingasync.annotaion.TinyShardingJdbcVo;
import com.tinyshardingjdbc.tinyshardingjdbc.shardingasync.core.TypeProcessor;
import com.tinyshardingjdbc.tinyshardingjdbc.shardingasync.core.YearMonthProcessor;
import com.tinyshardingjdbc.tinyshardingjdbc.shardingasync.tool.ExecutorPluginUtils;
import com.tinyshardingjdbc.tinyshardingjdbc.shardingasync.tool.TinyApplicationContext;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Invocation;

import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;


public class TinyShardingAsyncImpl {


    public List<Object> queryByPage(String tableStart,
                                    String tableEndDate,
                                    TinyShardingAsyncService shardingAsyncService,
                                    String tablePrefix,
                                    Object parameter,
                                    BoundSql boundSql, IPage<?> page,
                                    Invocation invocation, Map<String, Object> map, TinyShardingJdbcVo tinyShardingJdbcVo, String filed)
            throws Exception {
        TypeProcessor typeProcessor = (TypeProcessor) TinyApplicationContext.getBean(tinyShardingJdbcVo.getTinyShardingJdbc().clz());
        List<String> table = typeProcessor.getTableName(tableStart, tableEndDate, tablePrefix, filed, tinyShardingJdbcVo, invocation);
        Map<String, Object> parameterMap = (Map<String, Object>) parameter;
        List<ParameterMapping> ParameterList = boundSql.getParameterMappings();
        List<Object> parList = new ArrayList<>();

        for (ParameterMapping p : ParameterList) {
            String[] key = p.getProperty().split("\\.");
            JSONObject jsonObject = JSON.parseObject(JSONObject.toJSONString(parameterMap.get(key[0])));
            if (jsonObject.containsKey(key[1])) {
                parList.add(jsonObject.get(key[1]));
            }
        }
        String sql = boundSql.getSql();
        String doDataSql = ExecutorPluginUtils.dosql(sql, parList);
        String newCountSql = "select count(1) as total  from (" + doDataSql + ")t2";
        if (table != null && table.size() > 0) {
            List<Future<HashMap<String, Long>>> countFutureList = new ArrayList<>();
            for (String tableName : table) {
                String doCountSql = newCountSql.replace(tablePrefix, tableName);
                Future<HashMap<String, Long>> countFuture = shardingAsyncService.asyncCount(doCountSql, tableName);
                countFutureList.add(countFuture);
            }
            HashMap<String, Long> totalCountMap = new HashMap<>();

            for (Future<HashMap<String, Long>> future : countFutureList) {
                try {
                    HashMap<String, Long> countMap = future.get(120, TimeUnit.SECONDS);
                    totalCountMap.putAll(countMap);
                } catch (Exception e) {

                }
            }
            LongSummaryStatistics summaryStatistics = totalCountMap.values().stream().mapToLong((x) -> x).summaryStatistics();
            long totalCount = summaryStatistics.getSum();
            /**
            * 应该在排序处理 简单做个表排序---某种情况符合按照年月分表的逻辑并不适合其他
            *
            * */
            List<Object> entityList=new ArrayList<>();
            if(!sql.toUpperCase().contains("ORDER BY")){
                /**不排序交给默认的年月处理*/
                typeProcessor = (TypeProcessor) TinyApplicationContext.getBean(YearMonthProcessor.class);
            }
            entityList= (List<Object>) typeProcessor.orderByProcessor(shardingAsyncService,totalCountMap,table,tablePrefix,doDataSql,page,totalCount);

            page.setTotal(Integer.valueOf(String.valueOf(totalCount)));
            return entityList;
        } else {
            throw new Exception("分页需要传" + tinyShardingJdbcVo.getFiled() + "字段");
        }


    }


}
